/*
 * WindowListenerAdapter2.h
 *
 *  Created on: 2012-8-28
 *      Author: yangentao@gmail.com
 */

#ifndef WINDOWLISTENERADAPTER2_H_
#define WINDOWLISTENERADAPTER2_H_

#include "headers.h"
#include "WindowListener.h"

class KeyEvent {
public:
	HWND hWnd;
	DWORD key;
	DWORD msg;
	DWORD lParam;
	bool shiftDown;
	bool ctrlDown;
	bool altDown;
public:
	KeyEvent(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

	DWORD getRepeatCount();
	bool isKeyDown();
	bool isSysKeyDown();
	bool isKeyUp();
	bool isSysKeyUp();
	bool isUp();
	bool isDown();
	bool isSys();
};

class MouseEvent {
public:
	HWND hWnd;
	DWORD msg;
	int x;
	int y;
	DWORD wParam;
public:
	MouseEvent(HWND hWnd, DWORD ms, WPARAM wParam, LPARAM lParam);
	bool isLeftButtonDown();
	bool isLeftButtonUp();
	bool isRightButtonDown();
	bool isRightButtonUp();
	bool isLeftButtonDoubleClick();
	bool withControlDown();
	bool withShiftDown();
	bool withMidButtonDown();
	bool withRightButtonDown();
};

class WindowListenerAdapter: public WindowListener {
public:
	MsgResult onMessage(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

	boost::function<bool(HWND, HDC)> OnEraseBackground;

	boost::function<void(HWND, CREATESTRUCT*)> OnCreating;
	boost::function<void(HWND)> OnFinished;

	//WM_CREATE, HWND is created, but invisible, not return CreateWindow/CreateWindowEx
	//return true: continue; false: destroy the window
	boost::function<bool(HWND w, CREATESTRUCT* createStruct)> OnCreated;

	boost::function<void(HWND, HDC, PAINTSTRUCT*)> OnPaint;

	//WM_ACTIVATE
	//If the window is activated by a mouse click, it also receives a WM_MOUSEACTIVATE message
	//isActiving, true: active; false: inactive
	boost::function<void(bool isActiving, bool byMouse, bool isMinimize)> OnActivate;

	//return true: close the window;  false: prevent close window
	boost::function<bool(void)> OnClose;

	//WM_DESTROY is sent before the child windows are destroyed
	boost::function<void(void)> OnDestroy;

	//The WM_NCDESTROY message is sent after the child windows have been destroyed
	boost::function<void(void)> OnNcDestroy;

	//WM_KEYDOWN and WM_SYSKEYDOWN
	boost::function<bool(const KeyEvent& ke)> OnKeyDown;

	//WM_KEYUP and WM_SYSKEYUP
	boost::function<bool(const KeyEvent& ke)> OnKeyUp;

	boost::function<bool(const MouseEvent& me)> OnLeftButtonDown;
	boost::function<bool(const MouseEvent& me)> OnLeftButtonUp;
	boost::function<bool(const MouseEvent& me)> OnRightButtonDown;
	boost::function<bool(const MouseEvent& me)> OnRightButtonUp;
	boost::function<bool(const MouseEvent& me)> OnClick;
	boost::function<bool(const MouseEvent& me)> OnDoubleClick;

	boost::function<bool(const MouseEvent& me)> OnMouseMove;
	boost::function<bool(const MouseEvent& me)> OnMouseHover;
	boost::function<bool(const MouseEvent& me)> OnMouseLeave;
	boost::function<bool(const MouseEvent& me)> OnMouseEnter;

	//flag: SIZE_MAXHIDE/SIZE_MAXIMIZED/SIZE_MAXSHOW/SIZE_MINIMIZED/SIZE_RESTORED
	boost::function<void(UINT flag, WORD width, WORD height)> OnSize;

	//on WM_CREATE message, after onCreated invoked
	boost::function<void(void)> OnCreateChildren;

	//on WM_SIZE message, after onSize, after onCreateChildren
	boost::function<void(void)> OnLayoutChildren;

	//WM_COMMAND
	//for MENUINFO.dwStyle = MNS_NOTIFYBYPOS
	boost::function<void(HMENU menu, int itemPos)> OnMenuItemByPos;

	//WM_COMMAND
	//menuID may be 0 when user select the seprator menu item.
	boost::function<void(UINT menuID)> OnMenuItem;
	//WM_COMMAND
	boost::function<void(UINT accelID)> OnAccelerator;

	//menu or accelerator
	boost::function<void(UINT cmd)> OnCommand;

	//WM_COMMAND
	boost::function<void(UINT controlMsg, UINT controlID, HWND control)> OnControl;

	//WM_SYSCOMMAND
	//wParam ==SC_CLOSE
	boost::function<void(void)> OnSystemClose;
	//WM_SYSCOMMAND
	boost::function<void(void)> OnSystemContextHelp;
	//WM_SYSCOMMAND//SC_KEYMENU, SC_MOUSEMENU
	boost::function<void(bool isMouse, int x, int y, int key)> OnSystemMenu;
	//WM_SYSCOMMAND
	boost::function<void(void)> OnSystemMaximize;
	//WM_SYSCOMMAND
	boost::function<void(void)> OnSystemMinimize;
	//WM_SYSCOMMAND
	boost::function<void(void)> OnSystemRestore;
	//WM_SYSCOMMAND
	boost::function<void(void)> OnSystemHScroll;
	//WM_SYSCOMMAND
	boost::function<void(void)> OnSystemVScroll;
	//WM_SYSCOMMAND
	boost::function<void(void)> OnSystemSizing;

	//WM_SYSCOMMAND//SC_TASKLIST
	//Activates the Start menu.
	boost::function<void(void)> OnSystemTaskList;
	//WM_SYSCOMMAND
	boost::function<void(void)> OnSystemMove;
	//WM_SYSCOMMAND
	boost::function<void(void)> OnSystemMovePre;
	//WM_SYSCOMMAND
	boost::function<void(void)> OnSystemMoveNext;
	//WM_SYSCOMMAND
	boost::function<void(void)> OnSystemDefault;
	//WM_SYSCOMMAND
	boost::function<void(HWND toActive)> OnSystemHotKey;
	//WM_SYSCOMMAND
	boost::function<void(void)> OnSystemScreenSave;
	//WM_SYSCOMMAND//lowPower or shutoff,
	boost::function<void(bool isLowPower, bool isShutOff)> OnSystemMonitorPower;

	boost::function<void(HWND)> OnChildCreated;
	boost::function<void(HWND)> OnChildSetFocus;
	boost::function<void(HWND)> OnChildKillFocus;

	boost::function<void(HWND)> OnKillFocus;
	boost::function<void(HWND)> OnSetFocus;

};

inline KeyEvent::KeyEvent(HWND hWnd_, UINT uMsg, WPARAM wParam_, LPARAM lParam_) {
	altDown = ::isKeyDown(VK_MENU);
	shiftDown = ::isKeyDown(VK_SHIFT);
	ctrlDown = ::isKeyDown(VK_CONTROL);
	key = wParam_;
	lParam = lParam_;
	msg = uMsg;
	hWnd = hWnd_;
}

inline bool KeyEvent::isKeyDown() {
	return msg == WM_KEYDOWN;
}
inline bool KeyEvent::isSysKeyDown() {
	return msg == WM_SYSKEYDOWN;
}
inline bool KeyEvent::isKeyUp() {
	return msg == WM_KEYUP;
}
inline bool KeyEvent::isSysKeyUp() {
	return msg == WM_SYSKEYUP;
}
inline DWORD KeyEvent::getRepeatCount() {
	return (lParam & 0x0000FFFF);
}
inline bool KeyEvent::isUp() {
	return isKeyUp() || isSysKeyUp();
}
inline bool KeyEvent::isDown() {
	return isKeyDown() || isSysKeyDown();
}
inline bool KeyEvent::isSys() {
	return isSysKeyDown() || isSysKeyUp();
}

inline MouseEvent::MouseEvent(HWND hWnd_, DWORD msg_, WPARAM wParam_, LPARAM lParam) {
	msg = msg_;
	wParam = wParam_;
	x = GET_X_LPARAM(lParam);
	y = GET_Y_LPARAM(lParam);
	hWnd = hWnd_;
}
inline bool MouseEvent::isLeftButtonDown() {
	return msg == WM_LBUTTONDOWN;
}
inline bool MouseEvent::isLeftButtonUp() {
	return msg == WM_LBUTTONUP;
}
inline bool MouseEvent::isRightButtonDown() {
	return msg == WM_RBUTTONDOWN;
}
inline bool MouseEvent::isRightButtonUp() {
	return msg == WM_RBUTTONUP;
}
inline bool MouseEvent::isLeftButtonDoubleClick() {
	return msg == WM_LBUTTONDBLCLK;
}
inline bool MouseEvent::withControlDown() {
	return (wParam & MK_CONTROL) != 0;
}
inline bool MouseEvent::withShiftDown() {
	return (wParam & MK_SHIFT) != 0;
}
inline bool MouseEvent::withMidButtonDown() {
	return (wParam & MK_MBUTTON) != 0;
}
inline bool MouseEvent::withRightButtonDown() {
	return (wParam & MK_RBUTTON) != 0;
}

#endif /* WINDOWLISTENERADAPTER2_H_ */
